package com.example.socket.core;

import java.util.Objects;

/**
 * 请求对象
 */
public class Request<T> {
    /**
     * 构建没有附加信息体的请求对象实例
     *
     * @param command 通信指令
     * @param body 消息体内容
     * @return
     */
    public static <T> Request<T> valueOf(Command command, T body) {
        Request<T> result = new Request<T>();
        result.header = Header.valueOf((byte) 0, (short) 0, 0, 0, command);
        result.body = body;
        return result;
    }

    public static <T> Request<T> valueOf(Header header, T body) {
        Request<T> result = new Request<>();
        result.header = header;
        result.body = body;
        return result;
    }

    /**
     * 构建请求对象实例
     * @param message
     * @param body
     * @return
     */
    public static <T> Request<T> valueOf(Message message, T body) {
        Request<T> result = new Request<>();
        result.body = body;
        result.header = message.getHeader();
        return result;
    }

    private Header header;
    /** 消息内容 */
    private T body;

    public Header getHeader() {
        return header;
    }

    /**
     * 检查是否有指定的状态
     * @param checked
     * @return
     */
    public boolean hasState(int checked) {
        return header.hasState((short) checked);
    }

    /**
     * 添加状态
     *
     * @param added 被添加的状态
     */
    public void addState(short added) {
        header.addState(added);
    }

    /**
     * 移除状态
     *
     * @param removed 被移除的状态
     */
    public void removeState(short removed) {
        header.removeState(removed);
    }

    // Getter and Setter ...

    public Command getCommand() {
        return header.getCommand();
    }

    public T getBody() {
        return body;
    }

    public int getSn() {
        return header.getSn();
    }

    /**
     * 设置请求序号<br/>
     * 不需要指定，该属于由{@link SimpleClient}负责生成
     *
     * @param sn
     */
    public void setSn(int sn) {
        this.header.setSn(sn);
    }

    public int getState() {
        return header.getState();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Request<?> request = (Request<?>) o;
        return Objects.equals(header, request.header) &&
                Objects.equals(body, request.body);
    }

    @Override
    public int hashCode() {
        return Objects.hash(header, body);
    }
}
